Imports Office = Microsoft.Office.Core
Imports System.IO
Imports System.Security.Permissions
Imports ParanoidMike.Word2MediaWikiDotNet.Convert

' TODO: Add necessary <Assembly: > permissions requests here, if needed
' TODO: determine whether, for the single VSTO add-in Assembly, the permissions requests are better here, in the Convert module, or just keep them closest to the code for which they're intended (to increase re-usability)?

Public Class ThisAddIn

    ' Credits: This code is a more-or-less faithful a conversion of Word2MediaWikiPlus from VBA to VSTO.
    ' Original VBA macro code available here: http://sourceforge.net/projects/word2mediawikip/

#Region "Constants"

    Const CODEPLEX_SITE As String = "http://www.codeplex.com/Word2WikiDotNet"
    Const TEMPLATE_FILENAME As String = "Word2MediaWikiDotNetTemplate.dot"
    Const TOOLBAR_NAME As String = "Word2MediaWikiDotNet"

#End Region

#Region " Variables "
    
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks>
    ''' The CustomizationContext template & add-in must be declared at the class level so that the same object can be referenced at Startup and Shutdown.
    ''' </remarks>
    Private customizationTemplate As Word.Template
    Private customizationAddIn As Word.AddIn
    Private addInInstallPath As String ' The location of this AddIn's installed files
    Private userTemplatePath As String ' The location of the user's Template folder in their User Profile

    ' The toolbar and its buttons must be declared at the class level, according to Cindy Meister
    Private W2MWDotNet As Office.CommandBar

    ' using the WithEvents keyword relieves us of having to code very precise, brittle event handling code.
    Private WithEvents uiConfig As Office.CommandBarButton ' toolbar button for configuring the Add-In
    Private WithEvents uiConvert As Office.CommandBarButton ' toolbar button for performing the actual conversion
    Private WithEvents uiUpload As Office.CommandBarButton ' toolbar button for uploading graphic files to your MediaWiki site
    Private WithEvents uiReset As Office.CommandBarButton ' toolbar button for resetting the Toolbar, if the buttons no longer work

    ' Need to declare an instance of the Convert class so that non-shared members of the class can be referenced
    Dim DocumentConversion As ParanoidMike.Word2MediaWikiDotNet.Convert = New ParanoidMike.Word2MediaWikiDotNet.Convert

#End Region

#Region " Structures "

    ''' <summary>
    ''' Create a structure that will hold all the CommandBarButton settings.
    ''' </summary>
    ''' <remarks>
    ''' Intended to reduce the number of lines of code for creating these buttons.
    ''' </remarks>
    Private Structure CommandBarButtonSettings
        Friend BeginGroupProperty As Boolean
        Friend CaptionProperty As String
        Friend DescriptionTextProperty As String
        Friend FaceIDProperty As Integer
        Friend StyleProperty As Office.MsoButtonStyle
        Friend Tag As String
        Friend TooltipTextProperty As String
    End Structure

#End Region

#Region " Event Handlers "

    Private Sub ThisAddIn_Startup(ByVal sender As Object, _
                                  ByVal e As System.EventArgs) _
                                  Handles Me.Startup

        Try
            GetCustomizationTemplate() ' The CustomizationContext is required, at least in part, to ensure the CommandBar customizations are stored somewhere sensible (as Cindy Meister says in http://groups.google.com/group/microsoft.public.office.developer.com.add_ins/browse_thread/thread/1c9d651bb9f9333f/130bf07b8af4bfa5?hl=en&lnk=st&q=%22The+macro+cannot+be+found+or+has+been+disabled+because+of+your+Macro+security+settings%22+%22visual+studio%22#130bf07b8af4bfa5)
        Catch ex As ApplicationException
            If ex.Message = "BadOrNoTemplate"
                ' If the Template couldn't be found, then there's no point in trying to rest of the code (which will have many more exceptions as the toolbar and buttons ry to get hooked up)
                Exit Sub
            End If
            
        End Try
        InitializeUI(False) ' We don't want to destroy and recreate the UI elements at every startup, just minimally get a handle to them and ensure the code is connected to them
        ' NOTE: I disabled the following line of code because it's likely that some users would want to make the toolbar invisible, and this would override that configuration on each launch - and I don't want to interfere with user's rights to keep their configuration the way they like.
        'W2MWDotNet.Visible = True ' Ensure that the CommandBar is made visible in Word, just in case for whatever reason it's been made Not visible

    End Sub

    Private Sub ThisAddIn_Shutdown(ByVal sender As Object, _
                                   ByVal e As System.EventArgs) _
                                   Handles Me.Shutdown
        ' Enable the following .Save() operation if you're working with non-static customization templates
        'Me.customizationTemplate.Save ' Save the changes to the global CustomizationContext template, so the user doesn't get prompted

        ' TODO: anything we should remove/.Dispose, such as class-level Variables or even the CommandBar?

    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub uiConfig_Click(ByVal Ctrl As Microsoft.Office.Core.CommandBarButton, _
                               ByRef CancelDefault As Boolean) _
                               Handles uiConfig.Click
        MessageBox.Show("Configuration coming soon...")
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub uiConvert_Click(ByVal Ctrl As Microsoft.Office.Core.CommandBarButton, _
                                ByRef CancelDefault As Boolean) _
                                Handles uiConvert.Click

        DocumentConversion.InitializeActiveDocument()

        DocumentConversion.InitializeConversion()

        DocumentConversion.PerformConversion()

        DocumentConversion.FinishConversion(False)

    End Sub

    ''' <summary>
    ''' Call the AddCommandBar() and AddCommandBarButtons() procedures, passing in the parameter True to remove and replace the existing (presumably broken) buttons & toolbar.
    ''' </summary>
    ''' <param name="Ctrl"></param>
    ''' <param name="CancelDefault"></param>
    ''' <remarks>
    ''' Meant to be used only under circumstances in which the toolbar and/or its buttons (both of which persist from launch to launch of Word) no longer work "properly", and need to be reset to their install-time configuration.
    ''' </remarks>
    Private Sub uiReset_Click(ByVal Ctrl As Microsoft.Office.Core.CommandBarButton, _
                              ByRef CancelDefault As Boolean) _
                              Handles uiReset.Click

        AddCommandBar(True)
        AddCommandBarButtons(True)
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub uiUpload_Click(ByVal Ctrl As Microsoft.Office.Core.CommandBarButton, _
                               ByRef CancelDefault As Boolean) _
                               Handles uiUpload.Click
        MessageBox.Show("(not implemented yet)")

        ' Ideas:
        ' - have it check for a network connection
        ' - have it check for a server connection
        ' - have an exception handler for the case when the user hasn't been authenticated yet
    End Sub

#End Region

#Region " Private Subs "

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="replaceExistingToolbar"></param>
    ''' <remarks></remarks>
    Private Sub AddCommandBar(ByVal replaceExistingToolbar As Boolean)
        
        Dim _CommandBarsCollection As Office.CommandBars

        _CommandBarsCollection = DirectCast(Application.CommandBars, _
                                            Office.CommandBars)

        ' ******************************
        '  REMOVE Toolbar, if requested
        ' ******************************
        If replaceExistingToolbar = True Then
            W2MWDotNet = _CommandBarsCollection.FindControl(Tag:=TOOLBAR_NAME)
            If W2MWDotNet IsNot Nothing
                W2MWDotNet.Delete() ' I'm not sure this is necessary, but hopefully it can't hurt to be thorough.
                W2MWDotNet = Nothing
            End If
        End If


        ' ****************
        '  Add Toolbar
        ' ****************
        Try
            W2MWDotNet = Application.CommandBars(TOOLBAR_NAME)
            ' The CommandBar still exists
            ' TODO: is there anything more we need to do here, or just proceed with the handle to the toolbar already obtained?

        Catch ex As System.ArgumentException
            ' ************** Exception Text *******************************************
            ' System.ArgumentException: Value does not fall within the expected range.
            ' *************************************************************************
            ' This can occur when running W2MWPPBar = Application.CommandBars(TOOLBAR_NAME), if the toolbar does not exist

            ' Create a new CommandBar instance
            W2MWDotNet = _CommandBarsCollection.Add(TOOLBAR_NAME, _
                                                    Office.MsoBarPosition.msoBarTop, _
                                                    False, _
                                                    False)

            'MessageBox.Show(String.Format("{0} add-in's toolbar could not be found - you won't be able to upload to the Wiki until you restart Word and/or reinstall the Add-in.", TOOLBAR_NAME) _
            '                            + Environment.Newline + Environment.Newline + String.Format("Error: {0}", ex.Message), _
            '                            TOOLBAR_NAME, _
            '                            MessageBoxButtons.OK, _
            '                            MessageBoxIcon.Error)

        End Try

    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="replaceExistingButtons"></param>
    ''' <remarks></remarks>
    Private Sub AddCommandBarButtons(ByVal replaceExistingButtons As Boolean)

        Dim buttonSettings As New CommandBarButtonSettings()

        ' ************************
        '  Gather Button SETTINGS
        ' ************************

        ' This button controls the configuration of the W2MW.Net add-in
        buttonSettings.CaptionProperty = "Configure Word2MediaWiki.Net"
        buttonSettings.DescriptionTextProperty = String.Empty
        buttonSettings.FaceIDProperty = 277
        buttonSettings.StyleProperty = Office.MsoButtonStyle.msoButtonIconAndCaption
        buttonSettings.Tag = "W2MW.Net Config"
        buttonSettings.TooltipTextProperty = "Word2MediaWiki.Net - Add-in Configuration"

        If replaceExistingButtons = True Then
            DeleteButton(uiConfig, buttonSettings.Tag)
        End If

        uiConfig = CreateButton(buttonSettings)

        ' This button controls document conversion from Word format to MediaWiki format
        buttonSettings.CaptionProperty = "Convert to Wiki"
        buttonSettings.DescriptionTextProperty = "Converts Word Documents to MediaWiki format."
        buttonSettings.FaceIDProperty = 2144
        buttonSettings.StyleProperty = Office.MsoButtonStyle.msoButtonIconAndCaption
        buttonSettings.Tag = "W2MW.Net Convert"
        buttonSettings.TooltipTextProperty = "Word2MediaWiki.Net - Convert to MediaWiki syntax and upload formatted text"

        If replaceExistingButtons = True Then
            DeleteButton(uiConvert, buttonSettings.Tag)
        End If

        uiConvert = CreateButton(buttonSettings)

        ' This button controls the Upload Images functionality of the W2MWPP add-in
        buttonSettings.CaptionProperty = "Upload Images"
        buttonSettings.DescriptionTextProperty = String.Empty
        buttonSettings.FaceIDProperty = 38
        buttonSettings.StyleProperty = Office.MsoButtonStyle.msoButtonIconAndCaption
        buttonSettings.Tag = "W2MW.Net Upload"
        buttonSettings.TooltipTextProperty = "Word2MediaWiki.Net - Upload Images to wiki"

        If replaceExistingButtons = True Then
            DeleteButton(uiUpload, buttonSettings.Tag)
        End If

        uiUpload = CreateButton(buttonSettings)

    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="settings"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function CreateButton(settings As CommandBarButtonSettings) As Office.CommandBarButton
        Dim button As Office.CommandBarButton

        ' *************
        '  Add BUTTON
        ' *************
        ' Add the CommandBarButton described by the settings to the CommandBar
        
        'Create the CommandBarButton (if it doesn't exist)
        If W2MWDotNet.FindControl(Tag:=settings.Tag) Is Nothing Then
                button = CType(W2MWDotNet.Controls.Add(Office.MsoControlType.msoControlButton), _
                                                      Office.CommandBarButton)

            Try
                'Configure the button with all settings enumerated from the settings Structure
                With button
                    .Caption = settings.CaptionProperty
                    .DescriptionText = settings.DescriptionTextProperty
                    .FaceId = settings.FaceIDProperty
                    .Style = settings.StyleProperty
                    .Tag = settings.Tag
                    .TooltipText = settings.TooltipTextProperty
                End With

            Catch ex As System.Runtime.InteropServices.COMException
                If ex.ErrorCode = -2147467259 Then
                    ' System.Runtime.InteropServices.COMException (0x80004005): Error HRESULT E_FAIL has been returned from a call to a COM component.
                    '   at Microsoft.Office.Core._CommandBarButton.set_Style(MsoButtonStyle pstyle)
                    '  at Word2MediaWiki__.ThisAddIn.ThisAddIn_Startup(Object sender, EventArgs e) in \Word2MediaWiki++\ThisAddIn.vb:line 77
                    MessageBox.Show(String.Format("The {0} toolbar has misconfigured one of its buttons.  Please restart Word, and if this error recurs, please file a bug at {1}.", _
                                                  TOOLBAR_NAME, _
                                                  CODEPLEX_SITE) _
                                    + Environment.Newline _
                                    + Environment.Newline _
                                    + String.Format("Error: {0}", ex.Message), _
                                                    TOOLBAR_NAME, _
                                                    MessageBoxButtons.OK, _
                                                    MessageBoxIcon.Error)
                End If

            End Try

        Else
            ' If it already exists, do not create the CommandBarButton but just obtain a handle to it
            button = W2MWDotNet.FindControl(Tag:=settings.Tag)
        End If

    Return button

End Function

    ''' <summary>
    ''' This method is invoked when the caller elects to use this routine in the "toolbar reset" mode
    ''' </summary>
    ''' <param name="button"></param>
    ''' <param name="tag"></param>
    ''' <remarks></remarks>
    Private Sub DeleteButton(button As Office.CommandBarButton, tag As String)

        ' Remove the CommandBarButton if it exists
        button = W2MWDotNet.FindControl(Tag:=tag)
        If button IsNot Nothing Then
            button.Delete(False)
            button = Nothing
        End If

    End Sub

    ''' <summary>
    ''' Loads the add-in's Global Template.  If there isn't a copy in the user's Profile yet, then copy the "master" from the add-in's install location.
    ''' </summary>
    ''' <remarks>
    ''' These "Global Templates" are sometimes known as the "Customization Context", and are documented piecemeal in various places:
    '''     http://msdn2.microsoft.com/en-us/library/aa140287(office.10).aspx
    '''     http://word.mvps.org/faqs/customization/CheckIfAddinsInstalled.htm
    '''     http://word.mvps.org/faqs/customization/WhatTemplatesStore.htm
    '''     http://word.mvps.org/faqs/MacrosVBA/OrganizeMacros.htm
    '''     http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=414338&SiteID=1
    ''' </remarks>
    Private Sub GetCustomizationTemplate()

        addInInstallPath = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), _
                                        "ParanoidMike\Word2MediaWikiDotNet")
        ' NOTE: the userTemplatePath variable is no longer being used, but I'll leave this here in case someone is interested in an approach where there's a per-user Template they'd like to try.
        'userTemplatePath = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), _
        '                                "Microsoft\Templates")

        Try
            ' This follows the sample by Cindy Meister http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1817623&SiteId=1
            customizationAddIn = Me.Application.AddIns.Add(Path.Combine(addInInstallPath, TEMPLATE_FILENAME), _
                                                           True) ' This variable doesn't refer to the Add-in Assembly, but rather to the Global Template shipped as part of this solution
            customizationTemplate = Me.Application.Templates(Path.Combine(customizationAddIn.Path, _
                                                                          customizationAddIn.Name)) ' This is the fully qualified path and filename, combined
            Me.Application.CustomizationContext = customizationTemplate


        Catch ex As System.Runtime.InteropServices.COMException
            ' ErrorCode -2146822615 = "The add-in template is not valid"

            If ex.ErrorCode = -2146824128 Then ' ex.Message = "Bad file name", which is the result when the file does not exist
                ' Template was not found in the install directory - either it was accidently deleted or it has become corrupted
                ' There's nothing that can be done in code - user will have to Repair or Reinstall
                MessageBox.Show(String.Format("The add-in template {0} was not found in {1}", _
                                              TEMPLATE_FILENAME, _
                                              addInInstallPath) + _
                                System.Environment.NewLine + _
                                "Please Repair or Reinstall the Add-In.", _
                                ThisAddIn.TOOLBAR_NAME, _
                                MessageBoxButtons.OK, _
                                MessageBoxIcon.Error)

            ElseIf ex.ErrorCode = -2146823108 Then ' ex.Message = "Word cannot open this document template."
                MessageBox.Show(String.Format("The add-in template {0} was not found in {1}", _
                                              TEMPLATE_FILENAME, _
                                              addInInstallPath) + _
                                System.Environment.NewLine + _
                                "Please Repair or Reinstall the Add-In.", _
                                ThisAddIn.TOOLBAR_NAME, _
                                MessageBoxButtons.OK, _
                                MessageBoxIcon.Error)

            Else
                ' Unknown COMException
                MessageBox.Show("Exception while initializing the global template: " + _ 
                                ex.Message + _
                                Environment.Newline + _
                                "InnerException: " + ex.InnerException.ToString + _
                                "COM Error code: " + ex.ErrorCode)
            End If

            Throw New ApplicationException("BadOrNoTemplate")

        Catch ex As Exception
            MessageBox.Show("Exception while initializing the global template: " + _ 
                            ex.Message + _
                            Environment.Newline + _
                            "InnerException: " + ex.InnerException.ToString)

        End Try
    End Sub
    
    ''' <summary>
    ''' ' If False, get handle to existing toolbar; otherwise, delete & recreate (i.e. "reset") the toolbar.
    ''' </summary>
    ''' <param name="reset">
    ''' If True, this procedure will try to delete and then recreate the CommandBar and its CommandBarButtons
    ''' If False, this procedure will merely try to acquire handles to the previously-defined CommandBar and its CommandBarButtons
    ''' </param>
    ''' <remarks>
    ''' In the future, this procedure can provide hooks to the RibbonUI in Word 2007, and to the CommandBar in Word 2003.
    ''' </remarks>
    Private Sub InitializeUI(reset As Boolean)

            AddCommandBar(reset) ' add or get a handle to the Toolbar
            AddCommandBarButtons(reset) ' make sure the Toolbar's buttons are enabled
            If Not reset = False
                ' Save the contents of the toolbar to the Template, trying to avoid unneeded user prompts @ shutdown
                Try
                    Me.customizationTemplate.Save()
                Catch ex As Exception
                    ' An error we encountered if the Template file had the Read only attribute: System.Runtime.InteropServices.COMException (0x800A176B): Word cannot write to file.
                    MessageBox.Show("Word could not save changes to the template where the Word2MediaWikiDotNet add-in stores settings for its custom toolbar." + _
                                    System.Environment.NewLine + _
                                    "Error message = " + ex.Message)
                    ' TODO: parameterize this messagebox's String to substitute (CurrentNameOfApplication), (CurrentNameOfAddIn) for "Word", "Word2MediaWikiDotNet"
               End Try
            End If
    End Sub

#End Region

End Class